package com.tuuzed.android.sqlite;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;

import java.util.Arrays;

final class SQLiteHelper {
    private static final String TAG = "SQLiteHelper";
    private boolean echoSQL;


    SQLiteHelper(boolean echoSQL) {
        this.echoSQL = echoSQL;
    }

    /**
     * 插入数据
     *
     * @param database       数据库对象
     * @param table          表名
     * @param nullColumnHack nullColumnHack
     * @param values         插入的列名和值
     * @return 行号
     * @throws SQLException 失败时抛出异常
     */
    long insertOrThrow(@NonNull SQLiteDatabase database, @NonNull String table, @Nullable String nullColumnHack,
                       @NonNull ContentValues values) throws SQLException {
        if (echoSQL) {
            StringBuilder sql = new StringBuilder();
            sql.append("INSERT").append(" INTO ").append(table).append('(');
            int size = values.size();
            if (size > 0) {
                boolean first = true;
                for (String colName : values.keySet()) {
                    sql.append(!first ? ',' : "");
                    sql.append(colName);
                    first = false;
                }
                sql.append(") VALUES (");
                for (int i = 0; i < size; i++) {
                    sql.append((i > 0) ? ",?" : '?');
                }
            } else {
                sql.append(nullColumnHack).append(") VALUES (NULL");
            }
            sql.append(')');
            Log.d(TAG, "==> sql: " + sql);
            Log.d(TAG, "===> args: " + values.toString());
        }
        return database.insertOrThrow(table, nullColumnHack, values);
    }

    /**
     * 更新数据
     *
     * @param database    数据库
     * @param table       表名
     * @param values      更新的值
     * @param whereClause where语句
     * @param whereArgs   where参数
     * @return 受影响的行数
     * @throws SQLException 失败时抛出异常
     */
    int updateOrThrow(@NonNull SQLiteDatabase database,
                      @NonNull String table,
                      @NonNull ContentValues values,
                      @Nullable String whereClause,
                      @Nullable String[] whereArgs) throws SQLException {
        if (echoSQL) {
            StringBuilder sql = new StringBuilder(120);
            sql.append("UPDATE ");
            sql.append(table);
            sql.append(" SET ");
            boolean first = true;
            for (String colName : values.keySet()) {
                sql.append(!first ? "," : "");
                sql.append(colName);
                sql.append("=?");
                first = false;
            }
            appendClause(sql, " WHERE ", whereClause);
            Log.d(TAG, "==> sql: " + sql);
            Log.d(TAG, "values= " + values.toString());
            if (whereArgs != null) {
                Log.d(TAG, "==> args: " + Arrays.toString(whereArgs));
            }
        }
        return database.update(table, values, whereClause, whereArgs);
    }

    /**
     * 删除数据
     *
     * @param database    数据库
     * @param table       表名
     * @param whereClause where语句
     * @param whereArgs   where参数
     * @return 受影响的行数
     */
    int delete(@NonNull SQLiteDatabase database,
               @NonNull String table,
               @Nullable String whereClause,
               @Nullable String[] whereArgs) {
        if (echoSQL) {
            StringBuilder sql = new StringBuilder();
            sql.append("DELETE FROM ").append(table);
            appendClause(sql, " WHERE ", whereClause);
            Log.d(TAG, "==> sql: " + sql);
            if (whereArgs != null) {
                Log.d(TAG, "==> args: " + Arrays.toString(whereArgs));
            }
        }
        return database.delete(table, whereClause, whereArgs);
    }


    /**
     * 查询数据
     *
     * @param database    数据库
     * @param distinct    是否去重
     * @param table       表名
     * @param columns     列
     * @param whereClause where语句
     * @param whereArgs   where参数
     * @param groupBy     groupBy语句
     * @param having      having语句
     * @param orderBy     orderBy语句
     * @param limit       limit语句
     * @return 游标
     */
    Cursor query(@NonNull SQLiteDatabase database,
                 boolean distinct,
                 @NonNull String table,
                 @Nullable String[] columns,
                 @Nullable String whereClause,
                 @Nullable String[] whereArgs,
                 @Nullable String groupBy,
                 @Nullable String having,
                 @Nullable String orderBy,
                 @Nullable String limit) {
        if (echoSQL) {
            StringBuilder sql = new StringBuilder(120);
            sql.append("SELECT ");
            if (distinct) sql.append("DISTINCT ");
            if (columns != null && columns.length != 0) appendColumns(sql, columns);
            else sql.append("* ");
            sql.append("FROM ");
            sql.append(table);
            appendClause(sql, " WHERE ", whereClause);
            appendClause(sql, " GROUP BY ", groupBy);
            appendClause(sql, " HAVING ", having);
            appendClause(sql, " ORDER BY ", orderBy);
            appendClause(sql, " LIMIT ", limit);
            Log.d(TAG, "==> sql: " + sql);
            if (whereArgs != null) {
                Log.d(TAG, "==> args: " + Arrays.toString(whereArgs));
            }
        }
        return database.query(distinct, table, columns, whereClause, whereArgs, groupBy, having, orderBy, limit);
    }

    /**
     * 执行SQL语句
     *
     * @param database 数据库
     * @param sql      SQL语句
     * @throws SQLException 失败时抛出异常
     */
    void execSQL(@NonNull SQLiteDatabase database,
                 @NonNull String sql) throws SQLException {
        if (echoSQL) {
            Log.d(TAG, "==> sql: " + sql);
        }
        database.execSQL(sql);
    }

    /**
     * @param database 数据库
     * @param sql      SQL语句
     * @param bindArgs 绑定参数
     * @throws SQLException 失败时抛出异常
     */
    void execSQL(@NonNull SQLiteDatabase database,
                 @NonNull String sql,
                 @NonNull Object[] bindArgs) throws SQLException {
        if (echoSQL) {
            Log.d(TAG, "==> sql: " + sql);
            Log.d(TAG, "==> args: " + Arrays.toString(bindArgs));
        }
        database.execSQL(sql, bindArgs);
    }

    private static void appendColumns(StringBuilder sql, String[] columns) {
        boolean first = true;
        for (String column : columns) {
            if (!first) sql.append(',');
            sql.append(column);
            first = false;
        }
        sql.append(' ');
    }

    private static void appendClause(StringBuilder sql, String name, String clause) {
        if (!TextUtils.isEmpty(clause)) {
            sql.append(name);
            sql.append(clause);
        }
    }

}
